//
//  ChartView.swift
//  DSP
//
//  Created by tucici on 2024/5/15.
//

import UIKit
import Charts
@objc protocol ChartDelegate
{
    /// 图表中，数值被选中
    @objc func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight)
    ///图表中，空白区域被选中
    @objc optional func chartValueNothingSelected(_ chartView: ChartViewBase)
    /// 图形每个entriys 的颜色
    @objc optional func chartDataSet(_ datas:[ChartDataEntryBase])->ChartData
    
    @objc optional func stringForValue(_ value: Double, axis: AxisBase?) -> String
}
class ChartView: UIView {
    var bg_img : UIImageView!
    ///有效值，低于此值，设置透明，达到不显示的效果。有效值段---无效值段(透明效果)---有效值段，形成一种断层效果
    var validValue = 0
    ///  = true ，折线会串联起，有效值，无效值。 = false ，折线会穿过无效值段，直接从上个有效值链接下个有效值
    var ignoreInvalid = true
    var delegate:ChartDelegate?
    private var lastValidEntry : ChartDataEntry?
    var showLastEntry = true
    var setColor = "#FF4D4D"
    var setRadius = 0.5
    var setLineWidth : CGFloat = 1.0
    var axisDependency:YAxis.AxisDependency = .left
    var setFillColor : UIColor = UIColor.RGBA(255, 192, 201, 1)
    var needReset = true
    var xVals=[String]()
    override init(frame: CGRect) {
        super.init(frame: frame)
        initUI()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    func initUI(){
        bgHexColor = "#C0C0C0"
        
        bg_img = UIImageView()
        bg_img.image = UIImage(named: "bg_chart")
        bg_img.contentMode = .scaleAspectFill
        addSubview(bg_img)
        bg_img.snp.makeConstraints { make in
            make.edges.equalToSuperview().inset(20)
        }
    }
    ///数据
    var array = [CGFloat]()
    {
        didSet
        {
            resetLine()
            lastValidEntry = nil
            
            let enter_arr = array.enumerated().map{ChartDataEntry(x: Double($0.offset), y: Double($0.element))}
            let result = enter_arr.reduce(into: [[ChartDataEntry]]()) { partialResult, element in
                let lastArray = partialResult.last ?? [element]
                let new_condition = element.y >= Double(validValue) || ignoreInvalid ///条件1：当前元素是否有效值
                let old_condition = lastArray.last!.y >= Double(validValue) || ignoreInvalid//条件2:：上一个元素是否有效值
                if partialResult.count > 0 , new_condition == old_condition{///如果两个元素条件一样，则放入同一个数组
                    partialResult[partialResult.count - 1].append(element)
                }else{
                    partialResult.append([element])
                }
            }
            
            ///2,画线
            for sub in result{
                guard sub.count > 0, let entry = sub.last else{return}
                lastValidEntry = entry.y > Double(validValue) ? entry : lastValidEntry
                setupLine(sub)
            }
            
            ///默认最后一次有效选中状态
            if lastValidEntry != nil && showLastEntry{
                delegate?.chartValueSelected(chatView, entry: lastValidEntry!, highlight: Highlight())
            }
        }
    }
    
    ///数据
    var entries : [ChartDataEntry]!{
        didSet{
            resetLine()
            lastValidEntry = nil
            setupLine(entries)
        }
    }
    
    ///清除折线
    private func resetLine(){
        if needReset == false{return}
        chatView.data?.dataSets.removeAll()
    }
    
    ///添加折线
    private func setupLine(_ array:[ChartDataEntry])
    {
        guard let charData = delegate?.chartDataSet?(array) as? LineChartData else {
            dataSet(array)
            return }
        chatView.data?.clearValues()
        chatView.data = charData
    }
    
    ///自定义显示X | Y轴。比如在Y轴的指定刻度，显示加粗网格线
    func addCustomLine(_ axis:AxisBase, _ value:CGFloat)->ChartLimitLine{
        // 计算刻度值在 Y 轴上的位置比例
        //let valuePosition = (importantValue - yMin) / (yMax - yMin)
        
        // 创建 ChartLimitLine 对象并设置属性
        let limitLine = ChartLimitLine(limit: value, label: "")
        limitLine.lineWidth = 0.5
        limitLine.lineColor = .black
        limitLine.drawLabelEnabled = false
        limitLine.valueFont = .systemFont(ofSize: 10)
        limitLine.labelPosition = .rightTop
        
        // 将 ChartLimitLine 对象添加到 Y 轴
        axis.addLimitLine(limitLine)
        return limitLine
    }
    
    
    //lazy
    lazy var chatView:LineChartView =
    {
        let chat = LineChartView()
        addSubview(chat)
        chat.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        chat.setViewPortOffsets(left: 25, top: 10, right: 10, bottom: 15)
        //设置间隙
        chat.setExtraOffsets(left:0, top:0, right:0, bottom:0)
        //设置边框
        //chat.borderColor = UIColor.blue
        chat.borderLineWidth = 0.5
        chat.drawBordersEnabled = true
        //绘制网格背景
        chat.drawGridBackgroundEnabled = false
        chat.gridBackgroundColor = "#D8D8D8".color()
        //是否显示图例
        chat.legend.enabled = false
        //没有数据时显示
        chat.noDataText = ""
        //x y轴是否支持拖拽
        chat.scaleXEnabled = true
        chat.scaleYEnabled = true
        //是否支持xy轴同时缩放
        chat.pinchZoomEnabled = true
        //是否支持双击缩放
        chat.doubleTapToZoomEnabled = false
        //高亮点击
        chat.highlightPerTapEnabled = true
        //高亮拖拽
        chat.highlightPerDragEnabled = true
        //启用拖拽
        chat.dragEnabled = true
        
        chat.delegate = self
        
        //=*=*==*=*==*=*==*=*==*=*==*=*==*=*==*=*==*=*设置X | Y轴==*=*==*=*==*=*==*=*==*=*==*=*==*=*==*=*==*=*==*=*==*=*=//
        ///设置Y轴，
        var leftAxis: YAxis! = chat.leftAxis
        leftAxis = yAxis(obj: &leftAxis)
        ///设置Y轴显示的刻度
        leftAxis.axisMinimum = -20
        leftAxis.axisMaximum = 20
        leftAxis.labelCount = 8
        leftAxis.valueFormatter = self
        ///特别显示一条Y轴
        let line = addCustomLine(leftAxis,0)
        line.lineColor = "#CFCFCF".color()
        
        
        ///设置右边Y轴
        var rightAxis: YAxis! = chat.rightAxis
        rightAxis = yAxis(obj: &rightAxis)
        rightAxis.enabled = false
        
        
        ///设置X轴
        var bottomAxis: XAxis! = chat.xAxis
        bottomAxis = xAxis(obj: &bottomAxis)
        bottomAxis.valueFormatter = self
        //bottomAxis.valueFormatter = kAxisValueFormatter()
        //=*=*==*=*==*=*==*=*==*=*==*=*==*=*==*=*==*=*设置X | Y轴==*=*==*=*==*=*==*=*==*=*==*=*==*=*==*=*==*=*==*=*==*=*=//
        return chat
    }()
}

//MARK: - ChartViewDelegate
extension ChartView : ChartViewDelegate
{
    ///图表中，数值被选中
    func chartValueSelected(_ chartView: ChartViewBase, entry: ChartDataEntry, highlight: Highlight) {
        delegate?.chartValueSelected(chartView, entry: entry, highlight: highlight)
    }
    
    ///图表中，空白区域被选中
    func chartValueNothingSelected(_ chartView: ChartViewBase) {
        delegate?.chartValueNothingSelected?(chartView)
    }
    ///图表中，被缩放
    func chartScaled(_ chartView: ChartViewBase, scaleX: CGFloat, scaleY: CGFloat) {
        
    }
    
    ///图表中，图表被移动
    func chartTranslated(_ chartView: ChartViewBase, dX: CGFloat, dY: CGFloat) {
        
    }
}

//MARK: - IAxisValueFormatter
extension ChartView : AxisValueFormatter{
    func stringForValue(_ value: Double, axis: AxisBase?) -> String {
        let str = delegate?.stringForValue?(value, axis: axis)
        if str != nil{
            return str!
        }
        
        let i = Int(value)
        if i < xVals.count && i >= 0{
            return xVals[i]
        }
        return ""
    }
}


//MARK: - 折现图表chart的一些属性，和生成方法
extension ChartView{
    /// x_轴
    private func xAxis(obj:inout XAxis?)->XAxis?{
        var axisObj = obj ?? XAxis()
        guard let x_axis = axis(axisObj: axisObj) as? XAxis else{return axisObj}
        x_axis.labelPosition = .bottom // 设置标签的位置，可以是 .top（上方）或 .bottom（下方）
        x_axis.labelRotationAngle = 0.0// 设置标签的旋转角度
        axisObj = x_axis
        return axisObj
    }
    
    /// y_轴
    private func yAxis(obj:inout YAxis?)->YAxis?{
        var axisObj = obj ?? YAxis()
        guard let y_axis = axis(axisObj: axisObj) as? YAxis else{return nil}
        y_axis.labelPosition = .outsideChart // 设置标签的位置，可以是 .insideChart（图表内部）或 .outsideChart（图表外部）
        y_axis.labelAlignment = .center // 设置标签的对齐方式
        axisObj = y_axis
        return y_axis
    }
    
    /// 主抽象类
    private func axis(axisObj:AxisBase)->AxisBase?{
        axisObj.decimals = 0 ///设置刻度值的格式化器，并设置小数位数为0
        // 设置属性
        axisObj.axisLineWidth = 0.5 // 轴线的宽度
        axisObj.axisLineColor = .black // 轴线的颜色
        
        axisObj.labelFont = UIFont.systemFont(ofSize: 8) // 标签的字体
        //axisObj.labelCount = 6  // 标签的数量
        axisObj.labelTextColor = .black // 标签的颜色
        axisObj.drawLabelsEnabled = true // 是否绘制标签
        axisObj.forceLabelsEnabled = false //强制绘制标签
        
        axisObj.gridLineDashPhase = 1 // 网格线的虚线相位
        axisObj.gridLineDashLengths = [1.0, 1.0] // 网格线的虚线样式
        
        axisObj.drawGridLinesEnabled = true // 是否绘制网格线
        axisObj.gridLineWidth = 0.5 // 网格线的宽度
        axisObj.gridColor = .gray // 网格线的颜色
        
        axisObj.drawAxisLineEnabled = false // 是否绘制轴线
        axisObj.axisLineDashPhase = 0 // 轴线的虚线相位
        axisObj.axisLineDashLengths = [10.0, 5.0] // 轴线的虚线样式
        
        //axisObj.valueFormatter = self// 刻度值的格式化器
        
        axisObj.granularity = 1.0// 轴刻度的精度，决定了刻度值的间隔和显示的精确度
        //axisObj.granularityEnabled = false //是否启用轴刻度的精度控制
        
        //axisObj.centerAxisLabelsEnabled = false  // 是否将标签居中对齐
        
        //axisObj.axisMinimum = 0.0//轴的最小值
        //axisObj.axisMaxValue = 0.0//轴的最大值
        
        //axisObj.spaceMin = 1//轴的最小值额外的空间，
        //axisObj.spaceMax = 1//轴的最大值额外的空间
        return axisObj
    }
    
    ///设置折线
    private func dataSet(_ array:[ChartDataEntry]){
        
        let set = LineChartDataSet(entries:array, label:"test样式")
        let isValidLine = array[0].y > Double(validValue) || ignoreInvalid
        
        //折线颜色
        set.setColor(isValidLine ? setColor.color() : .clear )
        set.lineWidth = setLineWidth
        set.axisDependency = axisDependency////这个属性重要，以右边y轴为准
        set.mode = .cubicBezier//折线平滑类型
        set.drawCirclesEnabled = true //圆点
        set.circleRadius = setRadius
        set.circleColors = isValidLine ? [setColor.color()] : [.clear]
        set.drawCircleHoleEnabled = true // 圆孔
        set.circleHoleColor = .white
        //        set.circleHoleRadius = 2 //圆孔孔中心半径 这个半径要比圆圈半径小才可以看到空心圆效果
        set.drawFilledEnabled = true //使能填充 填充效果可以达到股票交易软件中分时图的效果
        set.drawValuesEnabled = false
        //        set.highlightEnabled = false//取消高亮点击，如果设置为NO则线上所有点将无法点击 这个属性设置一定要注意
        //        set.drawHorizontalHighlightIndicatorEnabled = true  //取消横向纵向辅助线
        //        set.drawVerticalHighlightIndicatorEnabled = true
        set.fillColor = isValidLine ? setFillColor : .clear
        
        ///赋值
        let chatData = LineChartData()
        chatData.append(set)
        chatView.data?.clearValues()
        chatView.data = chatData
    }
}
